package chen.yi.component.operate.log.config;

import chen.yi.component.operate.log.annotate.Username;
import com.google.auto.service.AutoService;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;

/**
 * Username注解处理器，编译时生成元数据文件
 * 继承AbstractProcessor实现编译时处理
 *
 * @author huat
 **/
@SupportedAnnotationTypes("chen.yi.component.operate.log.annotate.Username")
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public final class UsernameProcessor extends AbstractProcessor {
    private static final String FILE_NAME = "META-INF/username-methods";

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
//        cleanPreviousResources(); // 初始化时清理残留文件
    }

    /**
     * 处理被@Username注解的元素
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {

        // 获取所有被@Username注解的方法元素
        Set<? extends Element> elements = env.getElementsAnnotatedWith(Username.class);

        List<ExecutableElement> validMethods = new ArrayList<>();
        processingEnv.getMessager().printMessage(
                Diagnostic.Kind.NOTE,
                "开始处理@Username注解，找到" + elements.size() + "个元素");
        // 过滤出有效方法
        elements.stream()
                .filter(e -> e.getKind() == ElementKind.METHOD)
                .map(e -> (ExecutableElement) e)
                .filter(e -> e.getAnnotation(Username.class) != null)
                .filter(this::validateMethod)
                .forEach(validMethods::add);
        // 校验方法唯一性
        if (validMethods.size() > 1) {
            processingEnv.getMessager().printMessage(
                    Diagnostic.Kind.ERROR,
                    "只能存在一个@Username方法");
            return false;
        }
        if (!env.processingOver() && !validMethods.isEmpty()) {
            // 生成元数据文件
            try {
                FileObject file = processingEnv.getFiler()
                        .createResource(StandardLocation.CLASS_OUTPUT, "", FILE_NAME);

                // JDK 17优化后的写入方式
                Path targetPath = Paths.get(file.toUri());
                Path parentDir = targetPath.getParent();
                if (!Files.exists(parentDir)) {
                    Files.createDirectories(parentDir);  // 自动创建父目录
                }
                // 新增文件存在检查逻辑
                String content = ((TypeElement) validMethods.get(0).getEnclosingElement()).getQualifiedName()
                        + "#" + validMethods.get(0).getSimpleName() + "\n";
                Files.write(targetPath, content.getBytes(StandardCharsets.UTF_8),
                        StandardOpenOption.CREATE,
                        StandardOpenOption.WRITE,
                        StandardOpenOption.TRUNCATE_EXISTING);
            } catch (IOException e) {
                processingEnv.getMessager().printMessage(
                        Diagnostic.Kind.ERROR, "文件生成失败: " + e.getMessage());
            }
        }

        return true;
    }

    /**
     * 校验方法签名是否符合要求
     */
    private boolean validateMethod(ExecutableElement method) {
        List<? extends VariableElement> params = method.getParameters();
        if (params.size() != 1) {
            processingEnv.getMessager().printMessage(
                    Diagnostic.Kind.ERROR,
                    "方法必须包含1个参数，实际参数数量: " + params.size(),
                    method);
            return false;
        }
        if (!processingEnv.getTypeUtils().isSameType(
                params.get(0).asType(),
                processingEnv.getElementUtils().getTypeElement("jakarta.servlet.http.HttpServletRequest").asType()
        )) {
            processingEnv.getMessager().printMessage(
                    Diagnostic.Kind.ERROR,
                    "参数类型应为HttpServletRequest，实际类型: " + params.get(0).asType(),
                    method);
            return false;
        }
        return true;
    }


    /**
     * 清理残留文件
     */
    private void cleanPreviousResources() {
        try {
            FileObject file = processingEnv.getFiler()
                    .getResource(StandardLocation.CLASS_OUTPUT, "", FILE_NAME);
            if (file != null) {
                URI uri = file.toUri();
                if ("file".equals(uri.getScheme())) {
                    new File(uri).delete();
                }
            }
        } catch (FileNotFoundException e) {
            // 文件不存在可忽略
        } catch (IOException e) {
            processingEnv.getMessager().printMessage(
                    Diagnostic.Kind.WARNING, "清理旧文件失败: " + e.getMessage());
        }
    }
}
